package com.mp3.player.vos
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	import mx.collections.ArrayCollection;
	import mx.collections.Sort;
	import mx.collections.SortField;
	import mx.events.CollectionEvent;
	import mx.utils.UIDUtil;

	public class TrackList extends EventDispatcher
	{
		[Bindable]
		public var name:String;
		
		private var _tracks: ArrayCollection;
		
		private var _selectedTrack: Track;
		
		private var _totalLength: Number = 0;
		
		//save user preference is SO???????????????????
		[Bindable]
		public var repeat: Boolean = false;
		
		[Bindable]
		public var shuffle: Boolean = false;
		
		//used in shuffle mode
		private var _notPlayedTracks: ArrayCollection;
		
		private var _history: History;
		
		/**
		 * Constructor
		*/
		public function TrackList(name:String = null)
		{
			this.name = (name != null) ? name : UIDUtil.createUID();
			
			_notPlayedTracks = new ArrayCollection();
			
			_tracks = new ArrayCollection(); 
			
			
			_history = new History();
		}
		
		//-----------------------------------------------------------------------------
		//
		// Get and Set methods
		//
		//------------------------------------------------------------------------------
		[Bindable("selectedTrackChanged")]
		public function get selectedTrack(): Track
		{
			return _selectedTrack;
		}

		[Bindable("tracksChanged")]
		public function get tracks(): ArrayCollection
		{
			return _tracks;
		}
		
		[Bindable("totalLengthChanged")]
		public function get totalLength(): Number
		{
			return _totalLength;
		}
		//-----------------------------------------------------------------------------------------
		//
		// Add/remove tracks methods
		//
		//-----------------------------------------------------------------------------------------
		public function addTrack(track: Track): void
		{
			if (track != null)
			{
				_tracks.addItem(track);
				_notPlayedTracks.addItem(track);
				dispatchEvent(new Event("tracksChanged"));
				
				populateTracksIndexes();
				calculateTotalLength();
			}
		}
		
		public function addTracks(list: ArrayCollection): void
		{
			for each (var track: Track in list)
			{
				_tracks.addItem(track);
				_notPlayedTracks.addItem(track);
			}
			
			dispatchEvent(new Event("tracksChanged"));
			populateTracksIndexes();
			calculateTotalLength();
		}
		
		public function removeTrack(track: Track): void
		{
			if (_tracks.contains(track))
			{
				var index: int = _tracks.getItemIndex(track);
				_tracks.removeItemAt(index);
				
				if (_notPlayedTracks.contains(track))
				{
					index = _notPlayedTracks.getItemIndex(track);
					_notPlayedTracks.removeItemAt(index);
				}
				populateTracksIndexes();
				calculateTotalLength();
				dispatchEvent(new Event("tracksChanged"));
			}
		}
		
		public function removeTracks(list: ArrayCollection): void
		{
			for each (var track: Track in list)
			{
				_tracks.removeItemAt(_tracks.getItemIndex(track));
				
				if (_notPlayedTracks.contains(track))
					_notPlayedTracks.removeItemAt(_notPlayedTracks.getItemIndex(track));
			}
			
			populateTracksIndexes();
			calculateTotalLength();
			dispatchEvent(new Event("tracksChanged"));
		}
		
		//-----------------------------------------------------------------------------------------
		//
		// Navigation tracks methods
		//
		//-----------------------------------------------------------------------------------------
		/**
		 * Call this method is user cluck on track
		*/
		public function selectTrack(track: Track): void
		{
			if (_tracks.contains(track))
			{
				var index: int = _tracks.getItemIndex(track);
				
				if (!shuffle)
				{
					_notPlayedTracks.removeAll();
					for (var i: int = index + 1; i < _tracks.length; i++)
					{
						_notPlayedTracks.addItem(_tracks.getItemAt(i));
					}
				}
				
				_selectedTrack = track;
				dispatchEvent(new Event("selectedTrackChanged"));
			}
		}
		
		public function next():void
		{
			var track: Track;
			var index: int;
			
			if (shuffle)
			{
				if (_notPlayedTracks.length > 0)
				{
					//get item from _notPlayedTracks
					index = Math.round(Math.random() * (_notPlayedTracks.length - 1));
					track = _notPlayedTracks.getItemAt(index) as Track;
				}
			}
			else
			{
				//get item from tracks
				if (_notPlayedTracks.length > 0)
				{
					index = _tracks.getItemIndex(selectedTrack);
					
					index++;
					
					if (index >= _tracks.length && repeat)
					{
						index = 0;
					}
					
					if (index < _tracks.length)
					{
						track = _tracks.getItemAt(index) as Track;
					}
					
				}
			}
			
			if (track == null)
			{
				if (repeat)
				{
					// add all to not played
					_notPlayedTracks.removeAll();
					_notPlayedTracks.addAll(_tracks);
					
					index = (shuffle) ? (Math.round(Math.random() * (_notPlayedTracks.length - 1))) : 0;
					track = _notPlayedTracks.getItemAt(index) as Track;
				}
			}
			
			if (track != null)
			{
				if (_notPlayedTracks.contains(track))
				{
					index = _notPlayedTracks.getItemIndex(track);
					_notPlayedTracks.removeItemAt(index);
				}
				
				if (shuffle)
				{
					_history.push(track);
				}
			}
			
			_selectedTrack = track;
			dispatchEvent(new Event("selectedTrackChanged"));
		}
		
		public function prev():void
		{
			var track: Track;
			var currentTrack: Track = selectedTrack;
			var index: int;
			var nextUsed: Boolean = false;
			
			if (shuffle)
			{
				//return from history
				track = _history.pop() as Track
			}
			else
			{
				//retrun from list
				index = _tracks.getItemIndex(selectedTrack);
				
				index--;
				if (index < 0 && repeat)
				{
					index = _tracks.length - 1;
				}
				
				if (index >= 0)
				{
					track = _tracks.getItemAt(index) as Track;
				}
			}
			
			if (track != null)
			{
				_notPlayedTracks.addItemAt(currentTrack, 0);
			}
			
			_selectedTrack = track;
			dispatchEvent(new Event("selectedTrackChanged"));
		}
	
		/**
		 * Function to get track index
		 * @param value	Track
		 * @return int track index
		 */
		public function getTrackIndex(value: Track): int
		{
			return _tracks.getItemIndex(value);
		}
		
		/**
		 * Sort track list.
		 *  
		 * @param field String
		 * @param ascending Boolean
		 */		
		public function sort(field:String, ascending:Boolean = true): void
		{
			var sort:Sort = new Sort();
			sort.fields = [new SortField(field, false, !ascending)];
			tracks.sort = sort;
			tracks.refresh();
			
			populateTracksIndexes();
		}
		//-----------------------------------------------------------------------------------------
		//
		// Private methods
		//
		//-----------------------------------------------------------------------------------------
		private function populateTracksIndexes(): void
		{
			var i: int = 1;
			for each (var track: Track in _tracks)
			{
				track.index = i;
				i++;
			}
		}
		
		/**
		 * Calculates total length of tracks. 
		 */		
		private function calculateTotalLength(): void
		{
			_totalLength = 0;
			
			for each (var track: Track in _tracks)
			{
				_totalLength += track.length;
			}
			
			dispatchEvent(new Event("totalLengthChanged"));
		}
	}
}